import asyncio
import os
import time
from concurrent.futures import ThreadPoolExecutor

import requests
from m3u8 import load
from requests import RequestException

import constants
from logger import logger
from service.task_video_service import TaskVideoService
from service.video_category import VideoCategoryService
from service.video_service import VideoService

headers = {
    "origin": constants.WEBSITE_URL,
    "User-Agent": constants.BROWER_VERSION,
}


def download_file(url, filename):
    response = requests.get(url, stream=True)
    if response.status_code == 200:
        with open(filename, 'wb') as f:
            for chunk in response.iter_content(1024):
                f.write(chunk)
        return "ok"
    else:
        logger.error(f"下载失败，状态码: {response.status_code}")
        return "error"


def download_image(image_url, imgage_name, output_directory='downloads'):
    # 修改文件名的后缀为.js
    new_image_filename = imgage_name + '.js'
    image_path = os.path.join(output_directory, new_image_filename)

    if not os.path.exists(image_path):
        status = download_file(image_url, image_path)
        if status == "ok":
            logger.info(f"图片下载完毕，已保存为：{new_image_filename}")
        else:
            logger.error(f"图片下载失败，{image_url}")
    else:
        logger.info(f"文件已存在：{new_image_filename}")


def download_segments_from_m3u8(url, output_directory='downloads'):
    # 1. 下载 .m3u8 文件
    logger.info(f"正在下载文件：{url}")
    m3u8_response = requests.get(url)
    if m3u8_response.status_code == 200:
        file_name = 'index.m3u8'
        m3u8_path = os.path.join(output_directory, file_name).replace('\\', '/')

        with open(m3u8_path, 'w') as f:
            f.write(m3u8_response.text)

        # 2.加载并解析.m3u8 文件
        playlist = load(url, verify_ssl=False)
        base_uri = os.path.dirname(url)

        # 3. 下载.m3u8 中的所有片段，并保存
        all_downloaded = True
        for segment in playlist.segments:
            segment_url = base_uri + "/" + segment.uri
            segment_filename = os.path.join(output_directory, os.path.basename(segment.uri))
            if not os.path.exists(segment_filename):
                count = 0  # 重试次数
                while count < 3:
                    try:
                        logger.info(f"正在下载视频文件： {segment_url}")
                        status = download_file(segment_url, segment_filename)
                        if status == "ok":
                            break
                    except RequestException as e:
                        logger.error(f"请求错误: {e}")
                    except Exception as e:
                        logger.error(f"未知错误: {e}")
                    finally:
                        count += 1

                if status != "ok":
                    logger.error(f"下载失败，已达到最大重试次数: {segment_url}")
                    all_downloaded = False
                else:
                    logger.info(f"视频下载完毕：{segment_url}")

        if all_downloaded:
            logger.info("所有资源下载完毕.")
            return 0
        else:
            logger.info("部分资源未下载成功，请检查下载状态.")
            download_segments_from_m3u8(url, output_directory)
            return 0
    elif m3u8_response.status_code == 410:
        logger.info(f"视频已删除，请手动删除本地文件: {url}")
        return 1
    else:
        logger.info(f"无法获取 M3U8 文件, 状态码: {m3u8_response.status_code}")
        return 2


video_service = VideoService()
task_video_service = TaskVideoService()
video_category_service = VideoCategoryService()


def download_all_file():
    logger.info("采集最新视频任务启动....")
    start_time = time.time()  # 获取当前的时间作为开始时间
    video_list = task_video_service.get_all_video_path_list()
    video_category_list = video_category_service.get_list()

    # 单线程版本
    # for video in video_list:
    #     download(video)

    # 使用ThreadPoolExecutor来管理线程池
    with ThreadPoolExecutor(max_workers=8) as executor:
        # 提交下载任务到线程池，并收集Future对象
        futures = [executor.submit(download, video, video_category_list) for video in video_list]

        # 等待所有下载任务完成
        for future in futures:
            future.result()

    end_time = time.time()  # 获取当前的时间作为结束时间
    execution_time = end_time - start_time  # 计算差值得到执行时间
    logger.info(f"采集最新视频任务结束,执行时长：{execution_time} 秒")


def download(video, type_list):
    output_directory = os.path.dirname(constants.DOWNLOAD_PATH)
    output_directory = os.path.join(output_directory, video.get("id"))
    os.makedirs(output_directory, exist_ok=True)
    download_image(video.get("image_url"), video.get("v_id"), output_directory)
    is_down = download_segments_from_m3u8(video.get("video_path"), output_directory)
    if is_down == 0:
        video["type_id"] = find_video_type_id(video.get("type_name"), type_list)
        if video_service.save_video_source(video):
            logger.info("视频转存成功")
    elif is_down == 1:
        # 资源已被删除
        task_video_service.delete_task_video_by_id(video_id=video.get("id"))

def find_video_type_id(name,type_list):
    for type in type_list:
        o_name = type.get("name").strip().replace('\n', '').replace(' ', '')
        n_name = name.strip().replace('\n', '').replace(' ', '')
        if o_name == n_name:
            return type.get("id")
    return None


if __name__ == '__main__':
    asyncio.run(download_all_file())
